package hello;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.Transaction;

import persistence.HibernateUtil;
import auction.chapter05.model.BankAccount;
import auction.chapter05.model.BankAccount_Join;
import auction.chapter05.model.BankAccount_SingleTable;
import auction.chapter05.model.BankAccount_Union;
import auction.chapter05.model.CreditCard;
import auction.chapter05.model.CreditCard_Join;
import auction.chapter05.model.CreditCard_SingleTable;
import auction.chapter05.model.CreditCard_Union;
import auction.chapter05.model.UserPolymorphicPerConcrete;
import auction.chapter05.model.User_SingleTable;
import auction.chapter05.model.User_Union;

public class HelloWorldInheritanceAndCustomTypes
{
    public static void main(String[] args)throws Exception
    {
        /* Table per subclass, <joined-subclass>, parent class has table too */
        //perSubclassJoin();
        
        /* Table per class hierarchy, single table, <discriminator> + <subclass> */
        //perClassHierarchy();
        
        /*Table per concrete class with union, <union-subclass> PK must increment */
        //perConcreteClassWithUnion();
        
        /* Table per concrete class with implicit polymorphism 
         * no hierarchy definition in hbm.xml
         * */
        //perConcreteClass();
        userPolymorphicPerConcreteClass();
    }
	
    /**
     * Table per concrete class with implicit polymorphism 
     * @throws Exception
     */
	public static void perConcreteClass()throws Exception
	{
		Session s9=HibernateUtil.getSessionFactory().openSession();
		Transaction t9=s9.beginTransaction();
		
		CreditCard cc=new CreditCard();
		cc.setNumber("411111");
		s9.save(cc);
		
		BankAccount ba=new BankAccount();
		ba.setBankname("ccb");
		s9.save(ba);
		
		t9.commit();
		s9.close();
		
		Session s8=HibernateUtil.getSessionFactory().openSession();
		Transaction t8=s8.beginTransaction();
		List list=s8.createQuery("from auction.chapter05.model.BillingDetails").list();
		t8.commit();
		s8.close();
		
		
	}
	
	public static void userPolymorphicPerConcreteClass()throws Exception
	{
		Session s9=HibernateUtil.getSessionFactory().openSession();
		Transaction t9=s9.beginTransaction();
		
		UserPolymorphicPerConcrete user = new UserPolymorphicPerConcrete();
		
		CreditCard cc=new CreditCard();
		cc.setNumber("411111");
		cc.setOwner("ccccc");
		
		BankAccount ba=new BankAccount();
		ba.setBankname("ccb");
		ba.setOwner("babababa");
		
		user.setDefaultBillingDetails(cc);
		
		s9.save(cc);
		s9.save(ba);
		s9.save(user);
		
		t9.commit();
		s9.close();
		
		Session s8=HibernateUtil.getSessionFactory().openSession();
		Transaction t8=s8.beginTransaction();
		UserPolymorphicPerConcrete loadu = (UserPolymorphicPerConcrete)s8.load(UserPolymorphicPerConcrete.class, 1L);
		loadu.setName("qqq");
		s8.saveOrUpdate(loadu);
		//loadu.setDefaultBillingDetails(ba);
		//out("####### "+loadu.getDefaultBillingDetails().getOwner());
		t8.commit();
		s8.close();
		
		
	}
	
	public static void perConcreteClassWithUnion()throws Exception
	{
		Session s1=HibernateUtil.getSessionFactory().openSession();
		Transaction t1=s1.beginTransaction();
		
		User_Union wei=new User_Union("wei");
		
		CreditCard_Union cc=new CreditCard_Union();
		cc.setOwner("cc");
		cc.setNumber("411111");
		
		BankAccount_Union ba=new BankAccount_Union();
		ba.setOwner("ba");
		ba.setBankname("ccb");
		
		wei.addBillingDetails(cc);
		wei.addBillingDetails(ba);
		wei.setDefaultBillingDetails(cc);
		
		s1.save(cc);
		s1.save(ba);
		s1.save(wei);
				
		t1.commit();
		s1.close();
		

		
		Session s2=HibernateUtil.getSessionFactory().openSession();
		Transaction t2=s2.beginTransaction();
		
		/*
		User_Union u=(User_Union)s2.get(User_Union.class, 999L);
		User_Union u2=(User_Union)s2.get(User_Union.class, 1L);
		u2.setDefaultBillingDetails(u.getDefaultBillingDetails());
		out(u2.getBillingDetails().size());
		out("##########"+u.getDefaultBillingDetails().getOwner());
        */
		
		List list=s2.createQuery("from BillingDetails_Union").list();
		t2.commit();
		s2.close();
		
		
	}
	
	/**
	 * Single table
	 * @throws Exception
	 */
	public static void perClassHierarchy()throws Exception
	{
		Session s1=HibernateUtil.getSessionFactory().openSession();
		Transaction t1=s1.beginTransaction();
		
		User_SingleTable wei=new User_SingleTable("wei");
		
		CreditCard_SingleTable cc=new CreditCard_SingleTable();
		cc.setOwner("cc");
		cc.setNumber("411111");
		
		wei.addBillingDetails(cc);
		wei.setDefaultBillingDetails(cc);
		
		
		s1.save(cc);
		s1.save(wei);
				
		t1.commit();
		s1.close();
		
		
		Session s3=HibernateUtil.getSessionFactory().openSession();
		Transaction t3=s3.beginTransaction();
				
		BankAccount_SingleTable ba=new BankAccount_SingleTable();
		
		ba.setOwner("ba");
		ba.setBankname("ccb");
		s3.save(ba);
		
		t3.commit();
		s3.close();
		
		
		/*
		Session s2=HibernateUtil.getSessionFactory().openSession();
		Transaction t2=s2.beginTransaction();
		
		List list=s2.createQuery("from BillingDetails_SingleTable").list();
		
		
		User_SingleTable loadedWei=(User_SingleTable)s2.get(User_SingleTable.class, 1L);
		BillingDetails_SingleTable bd=loadedWei.getDefaultBillingDetails();
		//Narrow the proxy to the subclass, doesn't hit db
		CreditCard_SingleTable ccc=(CreditCard_SingleTable)s2.load(CreditCard_SingleTable.class, bd.getId());
		out(ccc.getNumber());
		out("############"+bd.getClass().getName());
		out("############"+ccc.getClass().getName()+" ");//+ccc.getNumber()
		
		
		User_SingleTable user=(User_SingleTable)s2.createCriteria(User_SingleTable.class)
						.add(Restrictions.eq("id", 1L))
						.setFetchMode("defaultBillingDetails", FetchMode.JOIN)
						.uniqueResult();
		
		out("############"+user.getClass().getName());
		out("############"+user.getDefaultBillingDetails().getClass().getName());
		
		t2.commit();
		s2.close();
		*/
	}
	
	public static void perSubclassJoin()throws Exception
	{
		Session s1=HibernateUtil.getSessionFactory().openSession();
		Transaction t1=s1.beginTransaction();
		
		CreditCard_Join cc=new CreditCard_Join();
		
		cc.setOwner("cc");
		cc.setNumber("411111");
		s1.save(cc);
				
		t1.commit();
		s1.close();
		
		Session s3=HibernateUtil.getSessionFactory().openSession();
		Transaction t3=s3.beginTransaction();
				
		BankAccount_Join ba=new BankAccount_Join();
		
		ba.setOwner("ba");
		ba.setBankname("ccb");
		s3.save(ba);
		
		t3.commit();
		s3.close();
		
		
		Session s2=HibernateUtil.getSessionFactory().openSession();
		Transaction t2=s2.beginTransaction();
		List list=s2.createQuery("from BillingDetails_Join").list();
		list=s2.createQuery("from CreditCard_Join").list();
		t2.commit();
		s2.close();
		
		
	}
	
	public static void getParent(Class clazz)
	{
		Class parent=clazz.getSuperclass();
	  if(parent !=null)
	  {
			System.out.println("###"+parent.getName());
			getParent(parent);
		}
	}
	
	static void out(Object obj)
	{
		System.out.println(obj);
	}
}
